<?php
/*
 * MiniMe - a minimalistic OStatus complient microblogging tool
 * Copyright (C) 2010, Tuomas Koski - koski.tuomas@gmail.com
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * This class will represent xml similar to this:
 * <?xml version="1.0" encoding="UTF-8"?>
 * <XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0" xmlns:hm="http://host-meta.net/xrd/1.0">
 *    <hm:Host>identi.ca</hm:Host>
 *    <Link rel="lrdd" template="http://identi.ca/main/xrd?uri={uri}">
 *       <Title>Resource Descriptor</Title>
 *    </Link>
 * </XRD>
 * 
 * @author     Tuomas Koski <koski.tuomas@gmail.com>
 * @copyright  Tuomas Koski
 * @license    http://www.gnu.org/licenses/lgpl.txt
 */

class Xrd_HostMeta {
    
    /**
     * @var Xrd_HostMeta_Host
     */
    private $host;
    /**
     * @var Xrd_HostMeta_TemplateLink
     */
    private $link;
    
    private $namespaces = array();
    
    const ELEMENT_XRD = "XRD";
    const HOSTMETA_NS_PREFIX = "hm";
    const HOSTMETA_NS = "http://host-meta.net/xrd/1.0";
    
    const KEY_HOST     = 'host';
    const KEY_TEMPLATE = 'template_URL';
    
    /**
     * 
     * @param Xrd_HostMeta_Host $host
     * @param Xrd_HostMeta_TemplateLink $link
     * @return Xrd_HostMeta
     */
    private function __construct($host, $link) {
        $this->setHost($host);
        $this->setLink($link);
    }
    
    private function setHost(Xrd_HostMeta_Host $host) {
        $this->host = $host;
    }
    
    private function setLink(Xrd_HostMeta_TemplateLink $link) {
        $this->link = $link;
    }
    
    public function getHostValue() {
        return $this->host->getHostValue();
    }
    
    public function getTemplateValue() {
        return $this->link->getTemplate();
    }
    
    public function addChildElement(Xrd_ChildElement $childElement) {
        $this->childElements[] = $childElement;
    }
    
    private function addNamespace($namespaceURI, $qualifiedName) {
        $this->namespaces['xmlns:' . $namespaceURI] = $qualifiedName;
    }
    
    /**
     * This method should return the XML version of the object, something
     * similart to this:
     * <?xml version="1.0" encoding="UTF-8"?>
     * <XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0" xmlns:hm="http://host-meta.net/xrd/1.0">
     *    <hm:Host>identi.ca</hm:Host>
     *    <Link rel="lrdd" template="http://identi.ca/main/xrd?uri={uri}">
     *       <Title>Resource Descriptor</Title>
     *    </Link>
     * </XRD>
     *  
     * @return unknown_type
     */
    public function asXML() {
        $dom = new DOMDocument('1.0', 'UTF-8');
        $dom->formatOutput = true;
        
        $xrd_element = $dom->createElementNS(Xrd::XRD_NS, self::ELEMENT_XRD);
        
        foreach ($this->namespaces as $namespaceURI => $qualifiedName) {
            $xrd_element->setAttributeNS('http://www.w3.org/2000/xmlns/', $namespaceURI, $qualifiedName);
        }
        
        $xrd_element->appendChild($this->host->asDOMElement($dom));
        $xrd_element->appendChild($this->link->asDOMElement($dom)); 
        
        $dom->appendChild($xrd_element);
        
        return $dom->saveXML();
    }
    
    /**
     * Builind funrgion will try to create HostMetaXRD object from XML.
     * 
     * Example XML expected:
     * <?xml version="1.0" encoding="UTF-8"?>
     * <XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0" xmlns:hm="http://host-meta.net/xrd/1.0">
     *    <hm:Host>identi.ca</hm:Host>
     *    <Link rel="lrdd" template="http://identi.ca/main/xrd?uri={uri}">
     *       <Title>Resource Descriptor</Title>
     *    </Link>
     * </XRD>
     * 
     * @param String $rawXml
     * @return Xrd_HostMeta
     */
    public static function buildFromRawXML($rawXml) {
        $dom = new DOMDocument();
        if(@$dom->loadXML($rawXml)) {
            return self::buildFromDom($dom);
        }
        throw new Exception("Invalid raw XML data provided!");
    }
    
    public static function buildFromDom(DOMDocument $dom) {
        
        $xrd_element = $dom->getElementsByTagName('XRD')->item(0);
        if (!$xrd_element) {
            throw new Exception("Invalid DOM object for XRD, missing XRD root");
        }

        // Check for host-meta host
        $host = $xrd_element->getElementsByTagName('Host')->item(0);
        if (!$host) { 
            throw new Exception("Invalid DOM object for XRD, missing host value.");
        }    
        $host = Xrd_HostMeta_Host::buildFromDOMElement($host);
        
        
        
        //$links = $xrd_element->getElementsByTagName('link')
        $link = null;
        foreach ($xrd_element->getElementsByTagName(Xrd_HostMeta_TemplateLink::ELEMENT_LINK) as $elm) {
            if($elm->getAttribute(Xrd_HostMeta_TemplateLink::ATTRIBUTE_REL) == "lrdd") {
                $link = Xrd_HostMeta_TemplateLink::buildFromDOMElement($elm);      
            }  
        }
        if(empty($link)) {
            throw new Exception("Invalid DOM object for XRD: template attribute not found from link elements.");           
        }
        $hm = new Xrd_HostMeta($host, $link);
        $hm->addNamespace(self::HOSTMETA_NS_PREFIX, self::HOSTMETA_NS);
        
        return $hm;
    }
    
    public static function buildFromArray(Array $array) {
        
        $host = new Xrd_HostMeta_Host($array[self::KEY_HOST]);
        $link = Xrd_HostMeta_TemplateLink::buildXrdHostMetaLink($array[self::KEY_TEMPLATE]);
        
        $hm = new Xrd_HostMeta($host, $link);
        $hm->addNamespace(self::HOSTMETA_NS_PREFIX, self::HOSTMETA_NS);
        
        return $hm;
    }
    
    /**
     * The static function is used to change the template http://identi.ca/main/xrd?uri={uri}
     * with $jid (pamela@gmail.com) to something like http://identi.ca/main/xrd?uri=acct:pamela@gmail.com
     * 
     * @param string $jid
     * @return string $uri 
     */
    public function generateUserXrdURL($uri) {
        return str_replace("{uri}", urlencode($uri), $this->link->getTemplate());        
    }
    
}